#ifndef __TESTS_SYSTEM__
#define __TESTS_SYSTEM__

#include <math.h>

#define D_USE_RDTSC

#ifdef D_USE_RDTSC
	typedef __int64 cycles_t;
#endif
#ifdef D_USE_QUERY_PERFORMANCE_COUNTER
	typedef double cycles_t;
#endif

void		init			();
void		release			();
cycles_t	get_cycles		();

#define I_FUNC_CALL_COUNT_PER_TEST	100
#define I_TEST_COUNT_PER_BUNCH		10000

#define BENCH( func, dRet, fTmp )\
{\
	cycles_t dRetTemp = 0;\
	for ( int j=0; j<I_TEST_COUNT_PER_BUNCH; j++ )\
	{\
		const float fVal = float( rand() );\
		cycles_t dStart = get_cycles();\
		for ( int i=0; i<I_FUNC_CALL_COUNT_PER_TEST; i++ )\
			fTmp += func( fVal + float(i) * 0.0000000001f ); \
		cycles_t dStop = get_cycles();\
		dRetTemp += dStop - dStart;\
	}\
	dRet = (double)dRetTemp / (double)I_TEST_COUNT_PER_BUNCH;\
}

#define BENCH_COMP( func1, func2, dRet1, dRet2, fTmp )\
{\
	cycles_t dRetTemp1 = 0;\
	cycles_t dRetTemp2 = 0;\
	float fTmp1 = 0.f;\
	float fTmp2 = 0.f;\
	for ( int j=0; j<I_TEST_COUNT_PER_BUNCH; j++ )\
	{\
		float fVal = float( rand() );\
		cycles_t dStart1 = get_cycles();\
		for ( int i=0; i<I_FUNC_CALL_COUNT_PER_TEST; i++ )\
			fTmp1 += func1( fVal + float(i) * 0.0000000001f ); \
		cycles_t dStop1 = get_cycles();\
		dRetTemp1 += dStop1 - dStart1;\
		cycles_t dStart2 = get_cycles();\
		for ( int i=0; i<I_FUNC_CALL_COUNT_PER_TEST; i++ )\
			fTmp2 += func2( fVal + float(i) * 0.0000000001f ); \
		cycles_t dStop2 = get_cycles();\
		dRetTemp2 += dStop2 - dStart2;\
	}\
	dRet1 = (double)dRetTemp1 / (double)I_TEST_COUNT_PER_BUNCH;\
	dRet2 = (double)dRetTemp2 / (double)I_TEST_COUNT_PER_BUNCH;\
	fTmp = (fTmp2 - fTmp1) / fTmp1;\
}

#define CPUCLOCKCOUNT( func ) \
{\
	float fTmp = 0.f;\
	double dSum;\
	BENCH( func, dSum, fTmp );\
	printf( " %s : \t\t%.2f      %.1f\n", #func, (float)dSum, fTmp );\
}

#define COMPARE_CPUCLOCKCOUNT( func1, func2 )\
{\
	float fTmp = 0.f;\
	double dSum1;\
	double dSum2;\
	BENCH_COMP( func1, func2, dSum1, dSum2, fTmp );\
	const double dDiff = dSum2 - dSum1;\
	const double dRelDiff = dDiff / dSum1;\
	const float fPerc = (float)dRelDiff * 100.f;\
	if ( fPerc < 0. )\
		printf( "+ %s - %s : \t\t%.2f%%    cycles: %.1f / %.1f    %.1f\n", #func1, #func2, fPerc, (float)dDiff, (float)dSum1, fTmp );\
	else\
		printf( "- %s + %s : \t\t %.2f%%    cycles: %.1f / %.1f    %.1f\n", #func1, #func2, fPerc, (float)dDiff, (float)dSum1, fTmp );\
}

#endif